package com.ruoyi.web.service;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.ruoyi.web.domain.NewsUpdate;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
public class NewsUpdateCrawlerService {
    @Autowired
    private NewsUpdateService newsUpdateService;

    private static final Logger logger = LoggerFactory.getLogger(NewsUpdateCrawlerService.class);

    private static final String BASE_URL = "http://www.zjtxgj.com";
    private static final String START_URL = BASE_URL + "/col.jsp?id=143";
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    public void crawlAllArticles() {
        List<NewsUpdate> allArticles = new ArrayList<>();

        try {
            List<NewsUpdate> oldRecordList = newsUpdateService.list(new LambdaQueryWrapper<NewsUpdate>().select(NewsUpdate::getLink));
            Set<String> oldRecordLinkSet = new HashSet<>();
            if(!CollectionUtils.isEmpty(oldRecordList)){
                oldRecordLinkSet = oldRecordList.stream().map(NewsUpdate::getLink).collect(Collectors.toSet());
            }

            // 获取第一页
            Document firstPage = Jsoup.connect(START_URL)
                    .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
                    .timeout(30000)
                    .get();

            // 获取总页数
            int totalPages = getTotalPages(firstPage);
            logger.info("检测到总页数: {}", totalPages);

            // 处理第一页
            processPage(firstPage, allArticles);
            logger.info("第一页处理完成，获取到 {} 篇文章", allArticles.size());

            // 处理后续页面（从第2页开始） 上生产时可以注释
//            for (int page = 2; page <= totalPages; page++) {
//                try {
//                    String pageUrl = buildPageUrl(page);
//                    logger.info("正在爬取第 {} 页: {}", page, pageUrl);
//
//                    Document pageDoc = Jsoup.connect(pageUrl)
//                            .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
//                            .timeout(30000)
//                            .get();
//
//                    int beforeSize = allArticles.size();
//                    processPage(pageDoc, allArticles);
//                    int newArticles = allArticles.size() - beforeSize;
//                    logger.info("第 {} 页处理完成，新增 {} 篇文章", page, newArticles);
//
//                    // 添加延迟，避免请求过快
//                    Thread.sleep(1000);
//
//                } catch (Exception e) {
//                    logger.error("处理第 {} 页时发生错误: {}", page, e.getMessage());
//                }
//            }

            // 获取每篇文章的详细内容
            fetchArticleContents(allArticles, oldRecordLinkSet);

        } catch (Exception e) {
            logger.error("爬取过程中发生错误: {}", e.getMessage(), e);
        }
        newsUpdateService.saveBatch(allArticles);
    }

    private int getTotalPages(Document document) {
        try {
            // 找到class为pageNext的前一个class为pageNo的元素
            Elements pageNextElements = document.select("span.pageNext");
            if (!pageNextElements.isEmpty()) {
                Element pageNext = pageNextElements.first();
                Element prevPageNo = pageNext.previousElementSibling();

                // 向前查找pageNo元素
                while (prevPageNo != null && !prevPageNo.hasClass("pageNo")) {
                    prevPageNo = prevPageNo.previousElementSibling();
                }

                if (prevPageNo != null && prevPageNo.hasClass("pageNo")) {
                    Element link = prevPageNo.selectFirst("a.js_pagination");
                    if (link != null) {
                        String dataHref = link.attr("data-href");
                        if (dataHref != null && !dataHref.isEmpty()) {
                            // 从data-href中提取页码
                            Pattern pattern = Pattern.compile("pageno=(\\d+)");
                            Matcher matcher = pattern.matcher(dataHref);
                            if (matcher.find()) {
                                return Integer.parseInt(matcher.group(1));
                            }
                        }
                    }
                }
            }

            // 如果上述方法失败，尝试从分页元素中查找最大页码
            Elements pageElements = document.select(".pageNo a");
            int maxPage = 1;
            for (Element pageElement : pageElements) {
                String pageText = pageElement.text();
                try {
                    int pageNum = Integer.parseInt(pageText);
                    if (pageNum > maxPage) {
                        maxPage = pageNum;
                    }
                } catch (NumberFormatException e) {
                    // 忽略非数字文本
                }
            }
            return maxPage;

        } catch (Exception e) {
            logger.warn("获取总页数失败，使用默认值1: {}", e.getMessage());
            return 1;
        }
    }

    private String buildPageUrl(int pageNumber) {
        return BASE_URL + "/col.jsp?m1254pageno=" + pageNumber + "&id=143";
    }

    private void processPage(Document document, List<NewsUpdate> articles) {
        // 查找所有新闻信息块
        Elements newsInfoElements = document.select(".m_news_info");

        for (Element newsInfo : newsInfoElements) {
            try {
                NewsUpdate article = extractArticleBasicInfo(newsInfo);
                if (article != null) {
                    articles.add(article);
                }
            } catch (Exception e) {
                logger.error("提取文章基本信息时发生错误: {}", e.getMessage());
            }
        }
    }

    private NewsUpdate extractArticleBasicInfo(Element newsInfo) {
        // 提取标题和链接
        Element titleElement = newsInfo.selectFirst(".news_title a.article_title");
        if (titleElement == null) {
            return null;
        }

        String title = titleElement.attr("title");
        if (title == null || title.isEmpty()) {
            // 如果title属性为空，尝试获取span中的文本
            Element titleSpan = titleElement.selectFirst("span.title_content");
            if (titleSpan != null) {
                title = titleSpan.text().trim();
            }
        }

        String relativeLink = titleElement.attr("href");
        String fullLink = BASE_URL + relativeLink;

        // 提取发布时间
        Element timeElement = newsInfo.selectFirst("span.normal_time");
        LocalDate publishTime = null;
        if (timeElement != null) {
            try {
                String timeText = timeElement.text().trim();
                publishTime = LocalDate.parse(timeText, DATE_FORMATTER);
            } catch (Exception e) {
                logger.warn("日期解析失败: {}", timeElement.text());
            }
        }

        return new NewsUpdate(title, publishTime, fullLink, null);
    }

    private void fetchArticleContents(List<NewsUpdate> articles, Set<String> oldRecordLinkSet) {
        Iterator<NewsUpdate> iterator = articles.iterator();
        while (iterator.hasNext()) {
            NewsUpdate article = iterator.next();
            try {
                if (oldRecordLinkSet.contains(article.getLink())) {
                    logger.info("文章链接已存在，跳过: {}", article.getTitle());
                    iterator.remove();
                    continue;
                }

                logger.info("正在获取文章内容 [{}]: {}", articles.size(), article.getTitle());

                Document detailDoc = Jsoup.connect(article.getLink())
                        .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
                        .timeout(30000)
                        .get();

                // 提取内容
                String content = extractArticleContent(detailDoc);
                article.setContent(content);

                // 添加延迟
                Thread.sleep(500);

            } catch (Exception e) {
                logger.error("获取文章内容失败: {} - {}", article.getTitle(), e.getMessage());
                article.setContent("内容获取失败: " + e.getMessage());
            }
        }
    }

    private String extractArticleContent(Document document) {
        StringBuilder contentBuilder = new StringBuilder();

        try {
            // 根据详情页源代码，内容在 class="richContent richContent0" 的div中
            Element contentElement = document.selectFirst("div.richContent.richContent0");

            if (contentElement != null) {
                // 提取所有段落文本
                Elements paragraphs = contentElement.select("p");
                for (Element paragraph : paragraphs) {
                    String text = paragraph.text().trim();
                    if (!text.isEmpty()) {
                        contentBuilder.append(text).append("\n\n");
                    }
                }

                // 如果没有找到段落，直接提取整个内容的文本
                if (contentBuilder.length() == 0) {
                    String fullText = contentElement.text().trim();
                    contentBuilder.append(fullText);
                }
            } else {
                // 备用选择器：尝试其他可能的内容容器
                contentElement = document.selectFirst(".newsDetail .formMiddleContent");
                if (contentElement != null) {
                    String text = contentElement.text().trim();
                    contentBuilder.append(text);
                } else {
                    contentBuilder.append("未找到文章内容");
                }
            }

        } catch (Exception e) {
            logger.error("提取文章内容时发生错误: {}", e.getMessage());
            contentBuilder.append("内容提取失败: ").append(e.getMessage());
        }

        String content = contentBuilder.toString().trim();
        return content.isEmpty() ? "文章内容为空" : content;
    }
}